#pragma once

#include <iostream>
#include <sys/epoll.h>
#include <string>

#include "Log.hpp"
#include "Comm.hpp"

using namespace log_ns;

static const int epoll_num = 64;

class Multiplex
{
public:
    virtual bool AddEvent(int fd, uint32_t events) = 0;
    virtual bool ModEvent(int fd, uint32_t events) = 0;
    virtual bool DelEvent(int fd) = 0;
    virtual int Wait(epoll_event revs[], int num, int timeout) = 0;
private:
};

class Epoller : public Multiplex
{
private:
    bool ModEventHandler(int fd, uint32_t events, int oper)
    {
        struct epoll_event ev;
        ev.data.fd = fd;
        ev.events = events;
        int n = ::epoll_ctl(_epfd, oper, fd, &ev);
        if (n < 0)
        {
            LOG(ERROR, "EPOLL_CTL: %s ERROR, fd: %d\n", EventsToString(events).c_str(), fd);
            return false;
        }
        LOG(INFO, "EPOLL_CTL: %s SUCCESS, fd: %d\n", EventsToString(events).c_str(), fd);
        return true;
    }

public:
    Epoller()
    {
        _epfd = epoll_create(epoll_num);
        if (_epfd < 0)
        {
            LOG(FATAL, "epoll_create error!\n");
            exit(EPOLL_CREATE_ERROR);
        }
    }

    virtual bool AddEvent(int fd, uint32_t events) override
    {
        return ModEventHandler(fd, events, EPOLL_CTL_ADD);
    }

    virtual bool ModEvent(int fd, uint32_t events) override
    {
        return ModEventHandler(fd, events, EPOLL_CTL_MOD);
    }

    virtual bool DelEvent(int fd) override
    {
        return 0 == ::epoll_ctl(_epfd, EPOLL_CTL_DEL, fd, nullptr);
    }
    virtual int Wait(struct epoll_event revs[], int num, int timeout)
    {
        return ::epoll_wait(_epfd, revs, num, timeout);
    }

private:
    int _epfd;
};

// class Poller : public Multiplex
// {
// };

// class Selecter : public Multiplex
// {
// };
